/*
 * Copyright 2009 BioTeam Inc
 * 
 * Licensed under License GNU LESSER GENERAL PUBLIC LICENSE version 3.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.gnu.org/copyleft/lesser.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.bioteam.appweb.submit;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import net.bioteam.appweb.model.Program;
import net.bioteam.appweb.model.ProgramBuilder;
import net.bioteam.common.utils.MyEntityManager;

public abstract class LocalBaseCommandSubmitter extends BaseCommandSubmitter
{
	
	public boolean canSubmit(UnfinishedJob job)
	{
		return true;
	}

	public UnfinishedJob submitCommand(UnfinishedJob job) throws Exception
	{
		File workdir = new File(job.getWorkdir());
		Map<String, String> valueMap = getProperties(workdir);
		Program p = ProgramBuilder.getProgram(job.getProgramName());
		ProgramValueBean bean = new ProgramValueBean(p);
		bean.setValueMap(valueMap);
		EntityManager manager = MyEntityManager.getEntityManager();

		try
		{
			int numoftask = 0;
			CommandPreProcessor preProcessor = null;
			if (bean.getValue(PRE_COMMAND) != null)
			{
				preProcessor = (CommandPreProcessor) Class.forName(bean.getValue(PRE_COMMAND)).newInstance();
				numoftask = preProcessor.preProcessor(job, bean);
			}
			CommandGenerator generator= GeneratorUtil.getCommandGenerator(bean);
			String script =generator.generateScript(bean, job);
			String binaryname=null;
			if (bean.getValue(MPIPREFIX) != null && generator.postProcessMPI())
			{
				String tokens[]=script.split(" ");
				binaryname=tokens[0];
				StringBuffer sb=new StringBuffer();
				for (int i=1; i<tokens.length; i++)
				{
					sb.append(" ");
					sb.append(tokens[i]);
				}
				script="$APP"+sb.toString();
				script = bean.getValue(MPIPREFIX) + " " + script;
			}
			job.setCmdline(script);

			if (bean.getValue(BULK_JOB) != null && bean.getValue(BULK_JOB).equals("1"))
			{
				if (numoftask != 0)
				{
					bean.setValue(BULK_NUM, String.valueOf(numoftask));
				}
			}

			//generate and submit script file.
			String scriptfile = generateScriptFile(job, bean, binaryname);
			new File(scriptfile).setExecutable(true);
			String jobid = submitScript(scriptfile, job, bean);

			job.setSubmittedTime(new Date());
			job.setCode(RunStatusCode.SUBMITTED);
			job.setJobid(jobid);
	
			if (preProcessor != null)
			{
				String postscript = preProcessor.getOutputScript(job, bean);
				if (postscript != null)
				{
					String postscriptfile = generatePostScriptFile(job, bean, postscript);
					new File(postscriptfile).setExecutable(true);

					String postjobid = submitPostScript(postscriptfile, job, bean, jobid);
					job.setJobid(postjobid);
				}
			}
			job.setTrials(job.getTrials() + 1);
			job.setNote("Submitted");
		} catch (Exception e)
		{
			job.setCode(RunStatusCode.FAILEDSUBMISSION);
			job.setTrials(job.getTrials() + 1);
			job.setNote(e.getMessage());
			throw e;
		} finally
		{
			EntityTransaction tx = manager.getTransaction();

			// only store the workdir name.
			tx.begin();
			manager.flush();
			tx.commit();

		}

		return job;

	}


	protected abstract String generateScriptFile(UnfinishedJob job, ProgramValueBean bean, String binaryname) throws IOException;

	protected abstract String generatePostScriptFile(UnfinishedJob job, ProgramValueBean bean, String postscript) throws IOException;

	protected abstract String submitPostScript(String filename, UnfinishedJob job, ProgramValueBean bean, String parentJobId) throws Exception;

	/**
	 * 
	 * @param filename
	 *            script file
	 * @param job
	 * @param bean
	 * @return jobid
	 * @throws Exception
	 */
	protected abstract String submitScript(String filename, UnfinishedJob job, ProgramValueBean bean) throws Exception;

}
